<?php
/**
 * Created by PhpStorm.
 * User: inhere
 * Date: 2016/03/4
 * Time: 15:30
 */

namespace app\extensions;

use Slim;
use slimExt\base\Collection;
use inhere\librarys\StdBase;
use inhere\librarys\helpers\ObjectHelper;

/**
 * Class MDerPage
 * @package app\extensions
 *
 *
 * @property-read string $dataFile
 * @property-read string $outputFile
 * @property string $page
 * @property string $real
 * @property string $suffix
 * @property bool $exists
 * @property bool $rendered
 *
 * @property array $rawAttr
 * @property array $pageAttr
 */
class MDerPager extends Collection
{
    protected $data = [
        'defaultPage' => 'index',

        // request page relative path
        'page' => '',

        // page path relative the project directory.
        'path' => '',

        // page relative path
        'real' => '',

        // page suffix
        'suffix' => '.html',

        // raw data file
        'dataFile' => '',

        // rendered static file
        'outputFile' => '',

        'exists' => true,

        // Have already rendered static file
        'rendered' => true,


        // raw data file own settings
        'rawAttr' => [],


        'handler'          => 'app\handlers\DefaultHandler',
        'parser'           => 'app\parsers\DefaultParser',
    ];

    /**
     * @var array
     */
    public $pageData = [];

    /**
     * @var array
     */
    public $pageAsset = [];

    /**
     * page belongs to which project.
     * projects config see '@src/config/config.yml' tag `projects`
     * @var Project
     */
    protected $project;

    const DEFAULT_FILE = 'index';
    const OUTPUT_SUFFIX = '.html';
    const SOURCE_SUFFIX = '.md';

    /**
     * 默认值
     * @var string
     */
    const DEFAULT_HANDLER = '\\app\\handlers\\DefaultHandler';

    /**
     * 默认值
     * @var string
     */
    const DEFAULT_PARSER = '\\app\parsers\\DefaultParser';

    /**
     * @param string $page
     */
    public function __construct($page='')
    {
        if ( $page ) {
            $this->prisePagePath($page);
        }

        parent::__construct();
    }

    /**
     * @param $page
     * @return $this
     */
    public function prisePagePath($page)
    {
        // clear space
        $page = $this->page = trim($page, '/ ');

        if ($page) {
            $this->data['real'] = $page;
            
            if( $suffix = get_extension($page) ) {
                $this->set('suffix', $suffix);
                $this->data['real'] = $page = substr($page, 0 , - (strlen($suffix)+1));
            }

            // find Page Project
            $this->findProject($page, $suffix);
        } else {
            $this->data['real'] = $this->data['defaultPage'];
        }
de($this, $this->project);
        return $this;
    }
    public function load($page)
    {
        return $this->prisePagePath($page);
    }

    /**
     * @param $page
     * @param $suffix
     * @return bool
     */
    protected function findProject($page, $suffix)
    {
        // find page belongs to which project.
        $copy = $page;
        $pos  = strpos($copy,'/');

        // fix: visit `/blog` , is project name, it real access page maybe is `/blog/index.md`.
        if ( !$suffix && $pos === false ) {
            $name = $copy;
        } else {
            $name = $pos>0 ? substr($copy, 0, strpos($copy,'/') ) : '';
        }

        /** @var MdpManager $pm */
        $pm = Slim::get('pm');
d($pm);
        if ( !($this->project = $pm->findProject($name)) ) {
            $this->data['path'] = $page;
            
            return false;
        }

        // 访问项目根路径。 访问设置的默认页
        if ( $name === $copy && $this->project->entryPage ) {
            $path = $this->project->entryPage;
        } else {
            $path = substr($page, $pos+1);
        }
        
        $this->data['path'] = $path;

        $this->loadPagerConfig($this->project);
        
        return true;
    }
    
    protected function loadPagerConfig(MdProject $p)
    {
        $this->pageData = $p->get('pageData', []);
        $this->pageAsset = $p->get('pageAsset', []);
        $this->data['handler'] = $p->get('handler', self::DEFAULT_HANDLER);
        $this->data['parser'] = $p->get('handler', self::DEFAULT_PARSER);
        $this->data['defaultPage'] = basename($p->defaultPage,self::SOURCE_SUFFIX);

        unset($p['pageData'], $p['pageAsset']);
    }

    /**
     * @return bool
     */
    public function findPageFile()
    {
        // 数据源目录中以下划线开始的文件或文件夹不会被读取。
        $projectName = $this->project->getName();
        $pageReal   = str_replace(['/', '\\'], DIR_SEP, $this->get('real'));

        $outputPath = $this->project->getOption('outPath') ? : $this->getOutput('path') . DIR_SEP . $projectName;
        $dataPath = $this->project->getOption('path') ? : $this->getSource('path') . DIR_SEP . $projectName;
        $outputPath = Slim::alias($outputPath);
        $dataPath = Slim::alias($dataPath);

        $this->outputFile = $outputPath . $pageReal . $this->getOutput('suffix', '.html');
        $this->dataFile   = $dataPath . $pageReal . $this->getSource('suffix','.md');

        // Have already rendered static file ?
        // if not exists, find raw data file
        if ( !file_exists($this->outputFile) ) {
            $this->rendered = false;
            $this->exists = file_exists($this->dataFile);

            // if dataFile not exists AND '$dataPath' is dir . find {@see $defaultFile} Page In Subdir
            if ( !$this->exists && is_dir($dataPath) ) {
                $this->findDefaultFileInSubdir($outputPath, $dataPath);
            }
        }

        return $this->exists;
    }

    /**
     * if '$dataPath' is dir, will check '$dataPath/index.md' is exists or not.
     * @param string $outputPath
     * @param string $dataPath
     * @return array|bool
     */
    protected function findDefaultFileInSubdir($outputPath, $dataPath)
    {
        $outSuffix = $this->getOutput('suffix', self::DEFAULT_OUTPUT_SUFFIX);
        $srcSuffix = $this->getSource('suffix', self::DEFAULT_SOURCE_SUFFIX);

        if ( ($default = $this->data['defaultPage']) && trim($this->data['page'],'/') === $this->getProjectName() ) {

            if ( substr($default,-3) === self::DEFAULT_SOURCE_SUFFIX ) {
                $default = substr($default, 0, -3);
            }

            $outputFile = Slim::alias($outputPath) . DIR_SEP . $default . $outSuffix;
            $dataFile   = Slim::alias($dataPath) . DIR_SEP . $default . $srcSuffix;

        } elseif ( $default = $this->get('default') ) {
            $outputFile = $outputPath . DIR_SEP . $default . $outSuffix;
            $dataFile   = $dataPath . DIR_SEP . $default . $srcSuffix;
        }

        $this->rendered = $this->exists = true;

        // Have already rendered static file ?
        if ( !file_exists($outputFile) ) {
            $this->rendered = false;

            // find raw data file
            if ( !($this->exists = file_exists($dataFile)) ) {
                return false;
            }
        }

        $this->set('real',  ($this->real === '/' ? '': $this->real ). '/' . $default)
             ->set('dataFile', $dataFile)
             ->set('outputFile', $outputFile);

        return true;
    }

    public function cacheRenderedData($data)
    {
        # code...
    }

    /**
     * @return boolean
     */
    public function isRendered()
    {
        return $this->get('rendered',false);
    }
        
    public function getBasePath()
    {
        if ($this->project) {
            return $this->project->path;
        }
        
        return Slim::$app->pm->getSourcePath();
    }
        
    public function getBaseOutPath()
    {
        if ($this->project) {
            return $this->project->outPath;
        }
        
        return Slim::$app->pm->getOutputPath();
    }

    /**
     * @return MderProject
     */
    public function getProject()
    {
        return $this->project;
    }

    /**
     * @return string
     */
    public function getProjectName()
    {
        return $this->project->getName();
    }

    /**
     * @param bool|false $output
     * @return string
     */
    public function getPageUrl($output=false)
    {
        return '/' . $this->getProjectName() . $this->get('real') . (
            $output ? $this->getOutput('suffix', '.html') : $this->getSource('suffix','.md')
        );
    }

    public static function checkPath($path)
    {
        $regex = '/^\/[a-zA-Z][\w-]{1,12}(?:\/[-.\w]+){0,6}\.md$/';
//        $regex = '/^/[a-zA-Z][\w-]{1,12}(?:/[\w-.]+){0,6}(?:.html|.md)?/';

        return preg_match($regex, $path) === 1;
    }
}
